
package com.naza.rpc.compiler;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.naza.rpc.compiler.weaver.ClassProxy;
import com.naza.rpc.compiler.weaver.ProxyProvider;

/**
 * @author yl
 */
public abstract class AbstractAccessAdaptive implements Compiler
{
    // package 正则表达式
    private static final Pattern PACKAGE_PATTERN = Pattern
            .compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");

    // 类名正则表达式
    private static final Pattern CLASS_PATTERN = Pattern
            .compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");

    // 类结束标志 }
    private static final String CLASS_END_FLAG = "}";

    protected ClassProxy factory = new ProxyProvider();

    protected NativeCompiler compiler = null;

    protected ClassLoader overrideThreadContextClassLoader(ClassLoader loader)
    {
        Thread currentThread = Thread.currentThread();
        ClassLoader threadContextClassLoader = currentThread
                .getContextClassLoader();
        if (loader != null && !loader.equals(threadContextClassLoader))
        {
            currentThread.setContextClassLoader(loader);
            return threadContextClassLoader;
        }
        else
        {
            return null;
        }
    }

    /**
     * 获取类加载器
     * 
     * @return
     */
    protected ClassLoader getClassLoader()
    {
        ClassLoader cl = null;
        try
        {
            cl = Thread.currentThread().getContextClassLoader();
        }
        catch (Throwable ex)
        {
        }
        if (cl == null)
        {
            cl = AbstractAccessAdaptive.class.getClassLoader();
            if (cl == null)
            {
                try
                {
                    // 如果以上都获取不到，使用系统类加载器
                    cl = ClassLoader.getSystemClassLoader();
                }
                catch (Throwable ex)
                {
                }
            }
        }
        return cl;
    }

    /**
     * 输出错误信息
     * 
     * @param e
     * @return
     */
    private String report(Throwable e)
    {
        StringWriter w = new StringWriter();
        PrintWriter p = new PrintWriter(w);
        p.print(e.getClass().getName() + ": ");
        if (e.getMessage() != null)
        {
            p.print(e.getMessage() + "\n");
        }
        p.println();
        try
        {
            e.printStackTrace(p);
            return w.toString();
        }
        finally
        {
            p.close();
        }
    }

    /**
     * 使用给定的类加载器对给定的代码进行编译
     * 
     * @see Compiler#compile(java.lang.String,
     *      java.lang.ClassLoader)
     */
    @Override
    public Class<?> compile(String code, ClassLoader classLoader)
    {
        code = code.trim();
        Matcher matcher = PACKAGE_PATTERN.matcher(code);
        String pkg;
        if (matcher.find())
        {
            //获取包名
            pkg = matcher.group(1);
        }
        else
        {
            pkg = "";
        }
        matcher = CLASS_PATTERN.matcher(code);
        String cls;
        if (matcher.find())
        {
            //获取类名
            cls = matcher.group(1);
        }
        else
        {
            throw new IllegalArgumentException("no such class name in " + code);
        }
        //获取类的全路径名
        String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls
                : cls;
        try
        {
            //加载类
            return Class.forName(className, true,
                    (classLoader != null ? classLoader : getClassLoader()));
        }
        catch (ClassNotFoundException e)
        {
            if (!code.endsWith(CLASS_END_FLAG))
            {
                //code 不完整
                throw new IllegalStateException(
                        "the java code not ends with \"}\", code: \n" + code
                                + "\n");
            }
            try
            {
                return doCompile(className, code);
            }
            catch (RuntimeException t)
            {
                throw t;
            }
            catch (Throwable t)
            {
                throw new IllegalStateException(
                        "failed to compile class, cause: " + t.getMessage()
                                + ", class: " + className + ", code: \n" + code
                                + "\n, stack: " + report(t));
            }
            finally
            {
                overrideThreadContextClassLoader(compiler.getClassLoader());
                compiler.close();
            }
        }
    }

    /**
     * 编译
     * @param clsName
     * @param javaSource
     * @return
     * @throws Throwable
     */
    protected abstract Class<?> doCompile(String clsName, String javaSource)
            throws Throwable;

    public ClassProxy getFactory()
    {
        return factory;
    }
}
